package com.googlecode.dgwt.client.dojo.impl;

import java.util.List;
import java.util.Map;

import com.googlecode.dgwt.client.dijit.Dijit;
import com.googlecode.dgwt.client.dojo.callback.TransformCallback;
import com.googlecode.dgwt.client.dojo.string.RegExp;


/**
 * @author	Wellington Tadeu dos Santos
 * @since	DGWT v0.01
 */
public class StringImpl {
    
    private RegExp nonProperCaseWordsRegex;
    
    /**
     * Performs parameterized substitutions on a string.
     * For example,
     *
     * dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]);
     * dojo.string.substitute("File '${name}' is not found in directory '${dir}'.", {name: "foo.html", dir: "/temp"});
     * 
     * both return
     * 
     * "File 'foo.html' is not found in directory '/temp'."
     * 
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param map hash to search for substitutions
     * @param transform a function to process all parameters before substitution takes place, e.g. dojo.string.encodeXML
     * @return String
     */
    public native String substitute(String text, Map<String,String> map, TransformCallback<String, String> transform) /*-{
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(transform.@com.googlecode.dgwt.client.dojo.callback.TransformCallback::transform(Ljava/lang/Object;Ljava/lang/Object;)(key, map.@java.util.Map::get(Ljava/lang/Object;)(key)));
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param array hash to search for substitutions
     * @param transform a function to process all parameters before substitution takes place, e.g. dojo.string.encodeXML
     * @return String
     */
    public native String substitute(String text, List<String> array, TransformCallback<String, String> transform) /*-{
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(transform.@com.googlecode.dgwt.client.dojo.callback.TransformCallback::transform(Ljava/lang/Object;Ljava/lang/Object;)(key, array.@java.util.List::get(I)(@java.lang.Integer::parseInt(Ljava/lang/String;)(key))));
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param transform a function to process all parameters before substitution takes place, e.g. dojo.string.encodeXML
     * @return String
     */
    public native String substitute(String text, TransformCallback<String, String> transform) /*-{
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(transform.@com.googlecode.dgwt.client.dojo.callback.TransformCallback::transform(Ljava/lang/Object;Ljava/lang/Object;)(key, null));
        });
    }-*/;

    
    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param map hash to search for substitutions
     * @return String
     */
    public native String substitute(String text, Map<String,String> map) /*-{
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(map.@java.util.Map::get(Ljava/lang/Object;)(key));
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param array hash to search for substitutions
     * @return String
     */
    public native String substitute(String text, List<String> array) /*-{
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(array.@java.util.List::get(I)(@java.lang.Integer::parseInt(Ljava/lang/String;)(key)));
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `${key}` to be replaced
     * @param array hash to search for substitutions
     * @return String
     */
    public native String substitute(String text, String ...array) /*-{
        array = @com.googlecode.dgwt.client.dojo.core.JsArray::as([Ljava/lang/Object;)(array);
        return !text ? "" : text.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(array[@java.lang.Integer::parseInt(Ljava/lang/String;)(key)]);
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `{key}` to be replaced
     * @param array hash to search for substitutions
     * @return String
     */
    public native String propertiesSubstitute(String text, List<String> array) /*-{
        return !text ? "" : text.replace(/\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(array.@java.util.List::get(I)(@java.lang.Integer::parseInt(Ljava/lang/String;)(key)));
        });
    }-*/;


    /**
     * Performs parameterized substitutions on a string.
     * @param text a string with expressions in the form `{key}` to be replaced
     * @param array hash to search for substitutions
     * @return String
     */
    public native String propertiesSubstitute(String text, String ...array) /*-{
        array = @com.googlecode.dgwt.client.dojo.core.JsArray::as([Ljava/lang/Object;)(array);
        return !text ? "" : text.replace(/\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(_f, key){
            return String(array[@java.lang.Integer::parseInt(Ljava/lang/String;)(key)]);
        });
    }-*/;


    /**
     * 
     * @param text
     * @return
     */
    public boolean isParameterized(String text){
        if (text == null) {
            return false;
        }
        int paramInd = text.indexOf("${") + 2;
        return paramInd >= 2 && text.indexOf("}", paramInd) > paramInd;
    }
    
    
    /**
     * 
     * @param html
     * @return
     */
    public native String escapeHTML(String html) /*-{
        return ((html||"")
            .replace(/&/g,'&amp;')
            .replace(/</g,'&lt;')
            .replace(/>/g,'&gt;')
            .replace(/'/g,'&#39;')
            .replace(/"/g,'&#34;'));
    }-*/;

    
    /**
     * 
     * @param html
     * @return
     */
    public native String unescapeHTML(String html) /*-{
        return ((html||"")
            .replace(/&amp;/g,'&')
            .replace(/&lt;/g,'<')
            .replace(/&gt;/g,'>')
            .replace(/&#39;/g,"'")
            .replace(/&#34;/g,'"'));
    }-*/;


    public native String toProperCase(String text) /*-{
        var nonWord = this.@com.googlecode.dgwt.client.dojo.impl.StringImpl::getNonProperCaseWordsRegex()();
        return !text ? "" : text.toLowerCase().replace(/(^|\s)(\S)(\S*)/g, function(i, a, b, c, d){
            return (a + (d == 0 || !nonWord.test(b+c) ? b.toUpperCase() : b) + c);
        });
    }-*/;


    /**
     * @return the nonProperCaseWordsRegex
     */
    public RegExp getNonProperCaseWordsRegex() {
        if (nonProperCaseWordsRegex == null) {
            nonProperCaseWordsRegex = RegExp.create(Dijit.MESSAGE_RESOURCES.nonProperCaseWordsRegex());
        }
        return nonProperCaseWordsRegex;
    }
    
}
